package se.kth.id2212.market;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.sql.ResultSet;
import java.util.StringTokenizer;

import se.kth.id2212.bankjdbc.Account;
import se.kth.id2212.bankjdbc.Bank;
import se.kth.id2212.bankjdbc.RejectedException;

public class Client {

    private static final String USAGE = "java bankrmi.Client <bank_url>";
    private static final String DEFAULT_BANK_NAME = "Nordea";
    private static final String DEFAULT_MARKET_NAME = "eBAY";
    Account account;
    Trader trader;
    Bank bankobj;
    Market marketobj;
    private String bankName;
    private String marketName;
    private String clientName = "";

    static enum CommandName {
        /* list
         * quit
         * help
         * listItem
         * myHistory
         * newAccount (String)accountName (String)password
         * deleteAccount (String)accountName      
         * logInAccount (String)accountName (String)password
         * balance (String)accountName
         * deposit (String)accountName (float)amount
         * withdraw (String)accountName (float)amount
         * buyItem (String)accountName (String)itemName (String)traderName
         * sellItem (String)accountName (float)amount (String)itemName 		
         * */

        newAccount,  deleteAccount, logInAccount, deposit, withdraw, balance, list,
         listItem, buyItem, sellItem, myHistory,
        quit, help;
    };

    public Client(String bankName, String marketName, String clientName) {
        this.bankName = bankName;
        this.marketName = marketName;
        this.clientName = clientName;

        try {
            bankobj = (Bank) Naming.lookup(bankName);
            marketobj = (Market) Naming.lookup(marketName);

        } catch (Exception e) {
            System.out.println("The runtime failed: " + e.getMessage());
            System.exit(0);
        }

        System.out.println("Connected to bank: " + bankName);
        System.out.println("Connected to market: " + marketName);
    }

    public Client(String clientName) {
        this(DEFAULT_BANK_NAME, DEFAULT_MARKET_NAME, clientName);
    }

    public void run() {
        BufferedReader consoleIn = new BufferedReader(new InputStreamReader(System.in));

        while (true) {
            System.out.print(clientName + "@" + bankName + "-" + marketName + ">");
            try {
                String userInput = consoleIn.readLine();
                execute(parse(userInput));
            } catch (RejectedException re) {
                System.out.println(re);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private Command parse(String userInput) {
        if (userInput == null) {
            return null;
        }

        StringTokenizer tokenizer = new StringTokenizer(userInput);
        if (tokenizer.countTokens() == 0) {
            return null;
        }

        CommandName commandName = null;
        String userName = null;
        String itemName = null;
        String traderName = null;
        String amount = null;
        int userInputTokenNo = 1;

        while (tokenizer.hasMoreTokens()) {
            switch (userInputTokenNo) {
                case 1:
                    try {
                        String commandNameString = tokenizer.nextToken();
                        commandName = CommandName.valueOf(CommandName.class, commandNameString);
                    } catch (IllegalArgumentException commandDoesNotExist) {
                        System.out.println("Illegal command");
                        return null;
                    }
                    break;
                case 2:
                    userName = tokenizer.nextToken();
                    break;
                case 3:
                    amount = tokenizer.nextToken();
                    break;
                case 4:
                    itemName = tokenizer.nextToken();
                    break;
                case 5:
                    traderName = tokenizer.nextToken();
                    break;
                default:
                    System.out.println("Illegal command");
                    return null;
            }
            userInputTokenNo++;
        }
        return new Command(commandName, userName, amount, itemName, traderName);
    }

    void execute(Command command) throws RemoteException, RejectedException {
        if (command == null) {
            return;
        }

        switch (command.getCommandName()) {
            case list:
                try {
                    for (String accountHolder : bankobj.listAccounts()) {
                        System.out.println(accountHolder);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
                return;
            case quit:
                System.out.println("Service canceled.");
                System.exit(1);
            case help:
                for (CommandName commandName : CommandName.values()) {
                    System.out.println(commandName);
                }
                return;
            case listItem:
                try {
                   // System.out.println(marketobj.allItem());
                    ResultSet rs_2 = marketobj.allItem();
                    while(rs_2.next()){
                        System.out.println("Item: "+ rs_2.getString(MarketImpl.ITEM) + " price: "+rs_2.getFloat(MarketImpl.PRICE) + " seller: "+rs_2.getString(MarketImpl.TRADER));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
                return;
            case myHistory:
                return;
        }

        // all further commands require a name to be specified
        String userName = command.getUserName();
        if (userName == null) {
            userName = clientName;
        }

        if (userName == null) {
            System.out.println("name is not specified");
            return;
        }

        String password = command.getPW_or_Amount();
        switch (command.getCommandName()) {
            case newAccount:
                clientName = userName;
                bankobj.newAccount(userName);
                trader = marketobj.newTrader(userName, password, bankobj);
                
                return;
            case deleteAccount:
                clientName = "Please log in";
                bankobj.deleteAccount(userName);
                marketobj.deleteTrader(userName);
                return;
            
        }

        // all further commands require a Account reference
        Account acc = bankobj.getAccount(userName);
        //Trader tradr = marketobj.getTrader(userName);
        if (acc == null) {
            System.out.println("No account for " + userName);
            return;
        } 
        else {
            account = acc;
           // trader = tradr;
            clientName = userName;
        }

        float amount = 0;
        String pw_or_amount = command.getPW_or_Amount();
        String itemName = command.getItemName();

        switch (command.getCommandName()) {
            case logInAccount:
                clientName = userName;
                
                trader = marketobj.logIn(userName, password,bankobj);
                
                break;
            case deposit:
                try {
                    amount = Float.parseFloat(pw_or_amount);
                    account.deposit(amount);
                } catch (NumberFormatException e) {
                    System.out.println("Illegal amount");
                }
                break;
            case withdraw:
                try {
                    amount = Float.parseFloat(pw_or_amount);
                    account.withdraw(amount);
                } catch (NumberFormatException e) {
                    System.out.println("Illegal amount");
                }
                break;
            case balance:
                System.out.println("balance: $" + account.getBalance());
                break;
            case sellItem:
                try {
                    amount = Float.parseFloat(pw_or_amount);
                    trader.sellItem(itemName, amount);
                } catch (NumberFormatException e) {
                    System.out.println("Illegal amount");
                }                
                break;
            case buyItem:
                trader.buyItem(itemName);
                break;
            default:
                System.out.println("Illegal command");
        }

    }

    private class Command {

        private String userName;
        private String pw_or_amount;
        private String itemName;
        private String traderName;
        private CommandName commandName;

        private String getUserName() {
            return userName;
        }

        private String getPW_or_Amount() {
            return pw_or_amount;
        }

        private String getItemName() {
            return itemName;
        }

        private String getTrader() {
            return traderName;
        }

        private CommandName getCommandName() {
            return commandName;
        }

        private Command(Client.CommandName commandName, String userName, String pw_or_amount, String itemName, String traderName) {
            this.commandName = commandName;
            this.userName = userName;
            this.pw_or_amount = pw_or_amount;
            this.itemName = itemName;
            this.traderName = traderName;
        }
    }

    public static void main(String[] args) {
        if ((args.length > 3) || (args.length > 0 && args[0].equals("-h"))) {
            System.out.println(USAGE);
            System.exit(1);
        }

        String bankName = null;
        String marketName = null;
        String clientName = null;

        if (args.length > 0) {
            bankName = args[0];
            marketName = args[1];
            clientName = args[2];
            new Client(bankName, marketName, clientName).run();
        } else {
            new Client(clientName).run();
        }
    }

}
